package com.demo;

import com.demo.util.CamelUtils;
import freemarker.cache.FileTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.junit.Test;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;

/**
 * @author gy
 * @date 2023/9/11
 */
public class GeneratorDTO {

    @Test
    public void generator() throws Exception {
        long startTime = System.currentTimeMillis();

        this.generatorInputDTO();
        this.generatorSelectInputDTO();
        this.generatorOutputDTO();

        long endTime = System.currentTimeMillis();
        System.out.println("总计耗时["+(endTime - startTime)+"]毫秒");
    }

    private static final String tableName = "t_enum_const";
//    private static final String tableName = "t_virtual_resource_manage";
//    private static final String tableName = "t_sample_manage";
//    private static final String tableName = "jtl_lxsj_luduan_now";

    private static final String inputPackagePath="D:\\generator\\src\\main\\java\\com\\sinoits\\" +
            "microservicehlyy\\dto\\input\\";
    private static final String entityPackagePath="D:\\generator\\src\\main\\java\\com\\sinoits\\" +
            "microservicehlyy\\test\\entity\\";
    private static final String entityInputDTOSuffix="InputDTO";
    private static final String fileType = ".java";

    private static final String tableNamePrefix = "t_";
    private static final String entityName =
            CamelUtils.line2upperCamel(tableName.replace(tableNamePrefix,""));

    //    ----------------------------------input dto------------------------------------------
    @Test
    public void generatorInputDTO() throws IOException {
        long startTime = System.currentTimeMillis();

        String fileName = entityPackagePath+entityName+fileType;

        // 读取文件内容到Stream流中，按行读取
        Stream<String> lines = Files.lines(Paths.get(fileName));

        System.out.println("-----------------生成 EntityInputDTO 开始-----------------------");

        File file = new File(inputPackagePath+entityName+entityInputDTOSuffix+fileType);
        // 如果存在，就删除旧的文件，保证是最新生成的文件
        if (file.exists()) {
            file.delete();
        }

        // forEach获取Stream流中的行数据不能保证顺序，但速度快。
        // 如果你想按顺序去处理文件中的行数据，可以使用forEachOrdered，但处理效率会下降
        lines.forEachOrdered(ele -> {
            ele = ele.replace("class "+entityName,"class "+entityName+entityInputDTOSuffix);
            if (!ele.contains("TableName") && !ele.contains("TableId") && !ele.contains("IdType") &&
                !ele.contains("是否删除") && !ele.contains("isDel") &&
                !ele.contains("创建时间 yyyy-MM-dd HH:mm:ss") && !ele.contains("LocalDateTime createTime") &&
                !ele.contains("修改时间 yyyy-MM-dd HH:mm:ss") && !ele.contains("LocalDateTime updateTime")){
                try {
                    fileWriterMethod(
                            inputPackagePath + entityName + entityInputDTOSuffix + fileType, ele);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
//            System.out.println(ele); //查看更改后的内容
        });

        long endTime = System.currentTimeMillis();
        System.out.println("***EntityInputDTO文件位置："+inputPackagePath+entityName+entityInputDTOSuffix+fileType);
        System.out.println("-----------------生成 EntityInputDTO 结束-----------------------");

        System.out.println("执行耗时["+(endTime - startTime)+"]毫秒");
    }


    /**
     * 方法 1：使用 FileWriter 写文件
     * @param filepath 文件目录
     * @param content  待写入内容
     * @throws IOException
     */
    public static void fileWriterMethod(String filepath, String content) throws IOException {
        try (FileWriter fileWriter = new FileWriter(filepath,true)) {
            fileWriter.append(content).append("\n");
        }
    }


    //    ----------------------------------select dto------------------------------------------

    private static final String selectPackagePath="D:\\generator\\src\\main\\java\\com\\sinoits\\" +
            "microservicehlyy\\dto\\input\\";

    private static final String entityInputDTOPrefix="Select";

    @Test
    public void generatorSelectInputDTO() throws IOException {
        long startTime = System.currentTimeMillis();

        String fileName = entityPackagePath+entityName+fileType;

        // 读取文件内容到Stream流中，按行读取
        Stream<String> lines = Files.lines(Paths.get(fileName));

        System.out.println("-----------------生成 SelectEntityInputDTO 开始-----------------------");

        File file = new File(selectPackagePath+entityInputDTOPrefix+entityName+entityInputDTOSuffix+fileType);
        // 如果存在，就删除旧的文件，保证是最新生成的文件
        if (file.exists()) {
            file.delete();
        }

        // forEach获取Stream流中的行数据不能保证顺序，但速度快。
        // 如果你想按顺序去处理文件中的行数据，可以使用forEachOrdered，但处理效率会下降
        lines.forEachOrdered(ele -> {
            ele = ele.replace("class "+entityName,"class "+
                    entityInputDTOPrefix+entityName+entityInputDTOSuffix + " extends PageInfoSize");
            if (!ele.contains("TableName") && !ele.contains("TableId") && !ele.contains("IdType") &&
                !ele.contains("是否删除") && !ele.contains("isDel") &&
                !ele.contains("创建时间 yyyy-MM-dd HH:mm:ss") && !ele.contains("LocalDateTime createTime") &&
                !ele.contains("修改时间 yyyy-MM-dd HH:mm:ss") && !ele.contains("LocalDateTime updateTime")){
                try {
                    fileWriterMethod(
                            selectPackagePath+entityInputDTOPrefix+entityName+entityInputDTOSuffix+fileType, ele);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
//            System.out.println(ele); //查看更改后的内容
        });

        long endTime = System.currentTimeMillis();
        System.out.println("***SelectEntityInputDTO文件位置："+selectPackagePath+entityInputDTOPrefix+entityName+entityInputDTOSuffix+fileType);
        System.out.println("-----------------生成 SelectEntityInputDTO 结束-----------------------");

        System.out.println("执行耗时["+(endTime - startTime)+"]毫秒");
    }


    //    ----------------------------------output dto------------------------------------------

    private static final String outputPackagePath="D:\\generator\\src\\main\\java\\com\\sinoits\\" +
            "microservicehlyy\\dto\\output\\";

    private static final String driver="com.mysql.cj.jdbc.Driver";

        private static final String ipAddrAndPort="192.168.6.35:23306";
//    private static final String ipAddrAndPort="127.0.0.1:3308";

    private static final String dbCatalog = "hlyy";

        private static final String username="sinoits";
//    private static final String username="root";

        private static final String password="sinoits@123";
//    private static final String password="123456";

    private static final String serverUrl ="jdbc:mysql://"+ipAddrAndPort+"?" +
            "useSSL=false&useUnicode=true&characterEncoding=utf8&autoReconnect=true" +
            "&rewriteBatchedStatements=TRUE&serverTimezone=Asia/Shanghai&allowMultiQueries=true" +
            "&useInformationSchema=true";//没有指定具体哪个数据库，现在获取的是整个连接
    private static final String url="jdbc:mysql://"+ipAddrAndPort+"/"+dbCatalog+"?" +
            "useSSL=false&useUnicode=true&characterEncoding=utf8&autoReconnect=true" +
            "&rewriteBatchedStatements=TRUE&serverTimezone=Asia/Shanghai&allowMultiQueries=true" +
            "&useInformationSchema=true";//指定hlyy数据库

    private static final String author = "gy";
    private static final String entityOutputDTOSuffix="OutputDTO";


    @Test
    public void generatorOutputDTO() throws Exception {
        long startTime = System.currentTimeMillis();
        //1，创建FreeMarker的配置类
        Configuration cfg=new Configuration();
        //2，指定模板加载器，将模板加入缓存中
        //文件路径加载器，获取到templates文件的路径
        String templates = this.getClass().getClassLoader().getResource("templates").getPath();
        FileTemplateLoader fileTemplateLoader=new FileTemplateLoader(new File(templates));
        cfg.setTemplateLoader(fileTemplateLoader);
        //3，获取模板
        Template template = cfg.getTemplate("EntityOutputDTO.ftl");
//        Template template = cfg.getTemplate("EntityOutputDTONoText.ftl");

        //4，构造数据模型
        Map<String, Object> map = buildModel();

        //5，文件输出
        /**
         * 处理模型
         *      参数一 数据模型
         *      参数二 writer对象（FileWriter（文件输出），printWriter（控制台输出））
         */
        System.out.println("-----------------生成 EntityOutputDTO 开始-----------------------");

        template.process(map,new FileWriter(
                new File(outputPackagePath+entityName+entityOutputDTOSuffix+fileType)));

        System.out.println("***EntityOutputDTO文件位置："+outputPackagePath+entityName+entityOutputDTOSuffix+fileType);
        System.out.println("-----------------生成 EntityOutputDTO 结束-----------------------");
        long endTime = System.currentTimeMillis();
        System.out.println("执行耗时["+(endTime - startTime)+"]毫秒");
    }

    /**
     * 构造数据模型
     * @return
     */
    private Map<String, Object> buildModel() throws Exception {

        //获取连接
        Class.forName(driver);//注册驱动
        Connection connection = DriverManager.getConnection(url, username,password);

        //获取元数据
        DatabaseMetaData metaData = connection.getMetaData();
        //获取数据库中表信息（mysql可以这样写，oracle会有一点区别）
        //参数1：当前操作的数据库 参数2：mysql可为空，oracle填写用户名（要大写） 参数3：null是查询所有表 非空是查询目标表 参数4：类型 table是表，view是视图
        ResultSet resultSet = metaData.getTables(dbCatalog, null, tableName, new String[]{"TABLE"});

        String TABLE_NAME = null;
        String REMARKS = null;
        while (resultSet.next()){
            //会打印出该数据库下的所有表名
            String TABLE_CAT = resultSet.getString("TABLE_CAT");
            String TABLE_SCHEM = resultSet.getString("TABLE_SCHEM");
            TABLE_NAME = resultSet.getString("TABLE_NAME");
            String TABLE_TYPE = resultSet.getString("TABLE_TYPE");
            REMARKS = resultSet.getString("REMARKS");
            System.out.printf("表类别:%s, 表模式:%s, 表名称:%s, 表类型:%s, 表描述:%s\n",
                    TABLE_CAT, TABLE_SCHEM, TABLE_NAME, TABLE_TYPE,REMARKS);
        }
        resultSet.close();
        connection.close();

        Map<String,Object> map=new HashMap<String, Object>();
        map.put("tableName",TABLE_NAME);
        map.put("entity",entityName);
        map.put("tableComment",REMARKS);

        String createDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        map.put("createDate",createDate);
        map.put("author",author);

        return map;
    }

}
